package org.eliza.base.coroutinesx

import kotlinx.coroutines.*

private fun jobCancel(times: Int) = runBlocking {
    println("=====jobCancel=====")
    val job = launch {
        println("job:sleeping")
        delay(1000L)
        println("job:end")
    }
    delay(times * 500L) // delay a bit
    println("main:   waiting!")
    job.cancel() // cancels the job 直接取消
    job.join() // waits for job's completion
    println("main:  quit.")
}

private fun jobCancelX(times: Int) = runBlocking {
    println("=====jobCancelX=====")
    val job = launch(Dispatchers.Default) {
        println("job:sleeping")
        delay(500L * times)
        println("job:end")
    }
    delay(1000L) // delay a bit
    println("main: waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: quit.")

}

private fun jobCancelXx(times: Int) = runBlocking {
    println("=====jobCancelX=====")
    val job = launch(Dispatchers.Default) {
        repeat(5) { i ->
            try {
                // print a message twice a second
                println("job: sleeping $i ...")
                delay(300L * times)
            } catch (e: Exception) {
                // log the exception
                println("err $i ${e.message}")
            }
        }
    }
    delay(1000L) // delay a bit
    println("main: waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: quit.")

}

private fun jobCancelFinally(times: Int) = runBlocking {
    println("=====jobCancelXxx=====")
    val job = launch(Dispatchers.Default) {
        try {
            repeat(3) { i ->
                println("job:sleeping $i ...")
                delay(300L * times)
            }
        } finally {
            println("job: I'm running finally")
        }
    }
    delay(1000L) // delay a bit
    println("main: waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: quit.")

}

private fun jobCancelWithContext(times: Int) = runBlocking {
    println("=====jobCancelXxx=====")
    val job = launch(Dispatchers.Default) {
        try {
            var begin = System.currentTimeMillis()
            var end = begin
            repeat(1000) { i ->
                println("job: ${end - begin} $i ...")
                delay(500L)
                begin = end
                end = System.currentTimeMillis()
            }
        } finally {
            withContext(NonCancellable) {
                val currentTimeMillis = System.currentTimeMillis()
                println("job: $currentTimeMillis finally")
                delay(1000L)
                println("job: ${System.currentTimeMillis() - currentTimeMillis} :NonCancellable")
            }
        }
    }
    delay(times * 1000L) // delay a bit
    println("main: waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: quit.")

}

private fun jobWithTimeout(times: Int) = runBlocking {
    println("=====jobWithTimeout=====")
    withTimeout(500L * times) {
        repeat(5) { i ->
            println("sleeping  $i ...")
            delay(500L)
        }
    }
}

private fun jobWithTimeoutOrNull(times: Int) = runBlocking {
    println("=====jobWithTimeoutOrNull=====")
    val result = withTimeoutOrNull(500L * times) {
        repeat(3) { i ->
            println("sleeping  $i ...")
            delay(500L)
        }
        //  times>3 --> return Done
        "Done" // will get cancelled before it produces this result
    }
    println("Result is $result")
}


private var acquired = 0

private class Resource {
    init {
        acquired++
    } // Acquire the resource

    fun close() {
        acquired--
    } // Release the resource
}

private fun jobOutArc(times: Int) {
    runBlocking {
        repeat(10_000) { // Launch 10K coroutines
            launch {
                val resource = withTimeout(60) { // Timeout of 60 ms
                    delay(50) // Delay for 50 ms
                    Resource() // Acquire a resource and return it from withTimeout block
                }
                resource.close() // Release the resource
            }
        }
    }
    // Outside of runBlocking all coroutines have completed
    println(acquired) // Print the number of resources still acquired
}

private fun jobOutArcX(times: Int) {
    runBlocking {
        repeat(10_000) { // Launch 10K coroutines
            launch {
                var resource: Resource? = null // Not acquired yet
                try {
                    withTimeout(60) { // Timeout of 60 ms
                        delay(50) // Delay for 50 ms
                        resource = Resource() // Store a resource to the variable if acquired
                    }
                    // We can do something else with the resource here
                } finally {
                    resource?.close() // Release the resource if it was acquired
                }
            }
        }
    }
    // Outside of runBlocking all coroutines have completed
    println(acquired) // Print the number of resources still acquired
}

fun main() {
//    jobCancel(2)
//    jobCancelX(5)
//    jobCancelXx(2)
//    jobCancelXxx(1)
//    jobCancelWithContext(3)
//    jobWithTimeout(2)
//    jobWithTimeoutOrNull(2)
    for (i in 0..10) {
        jobOutArc(2)
    }
    println("--------")
    for (i in 0..10) {
        jobOutArcX(2)
    }

}